<template>
    <div>
        <!-- <h3>添加或修改SPU时需要用到的页面结构</h3> -->
        <!-- 注：此处使用了属性“label-width”来为标签设置宽度，且根据Element官方的文档中的介绍，作为“Form”直接子元素的“form-item”会继承这个属性值（因此可以使用这个属性来为表单项的标签批量设置相同的宽度）。可以使用“auto”作为属性值↓ -->
        <el-form label-width="100px">
            <el-form-item label="SPU名称">
                <el-input placeholder="请您输入SPU名称"
                    v-model="anObjectBeUsedToStoreTheSpuThatHaveBeenHad.spuName"></el-input>
            </el-form-item>
            <el-form-item label="SPU品牌">
                <el-select>
                    <!-- <el-option label="华为"></el-option>
                    <el-option label="OPPO"></el-option>
                    <el-option label="vivo"></el-option>
                    <el-option label="小米"></el-option> -->
                    <el-option v-model="anObjectBeUsedToStoreTheSpuThatHaveBeenHad.tmId" :label="item.tmName"
                        :value="item.id" v-for="(item, index) in anArrayBeUsedToStoreAllOfTheTrademarkInfomation"
                        :key="item.id"></el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="SPU描述">
                <el-input placeholder="请您输入SPU描述" type="textarea"
                    v-model="anObjectBeUsedToStoreTheSpuThatHaveBeenHad.description"></el-input>
            </el-form-item>
            <el-form-item label="SPU照片">
                <!-- 使用“el-upload”组件提供的“照片墙”功能（
                 注：1.属性“v-model:file-list”的值表示“默认上传的文件”；
                 2.属性“action”的值是“上传图片时需要用到的接口地址”（特别注意：网址中需要携带公共前缀——“/api”，否则开发服务器不会做代理，也就不会转发请求）；
                 3.属性“list-type”的值是“文件列表的类型”。它可接收三个值：“text”（表示“只显示文件名”）、“picture”（表示“同时显示文件名和小型缩略图”）、“picture-card”（表示“显示大型缩略图”（即显示“照片墙”）））；
                 4.属性“on-preview”表示“点击文件列表中已上传的文件时的被调用的钩子函数”
                 5.属性“on-remove”的值是“在文件列表中移除文件时被调用的钩子函数”↓ -->
                <el-upload v-model:file-list="imageList" :before-upload="handlerForBeforeUpload"
                    action="/api/admin/product/fileUpload" list-type="picture-card"
                    :on-preview="handlerForPictureCardPreview" :on-remove="handlerForRemoveFile">
                    <el-icon>
                        <Plus />
                    </el-icon>
                </el-upload>
                <el-dialog v-model="isThedialogForPriviewPictureVisible">
                    <img w-full :src="UrlForPreviewImageInThedialog" alt="Preview Image"
                        style="height: 100%;width: 100%;" />
                </el-dialog>
            </el-form-item>
            <el-form-item label="SPU销售属性">
                <!-- 展示“销售属性”的下拉菜单↓ -->
                <el-select v-model="aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute"
                    :placeholder="saleAttributesThatUnSelectedByTheUser.length ? `还未选择${saleAttributesThatUnSelectedByTheUser.length}个` : `无`">
                    <!-- <el-option label="华为"></el-option>
                    <el-option label="OPPO"></el-option>
                    <el-option label="vivo"></el-option>
                    <el-option label="小米"></el-option> -->
                    <!-- 注：此处使用了“value”属性来收集（绑定）数据，并使用了“模板字符串”来拼接要收集的销售属性的ID和名称。在此处，模板字符串中的“冒号”起到了“分隔符”的作用，用于后续分割ID和名称↓ -->
                    <el-option v-for="(item, index) in saleAttributesThatUnSelectedByTheUser" :key="item.id"
                        :label="item.name" :value="`${item.id}:${item.name}`"></el-option>
                </el-select>
                <!-- 当变量“aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute”的值不为空时，表示用户已经选择了某个销售属性，此时，不为按钮添加“禁用效果”（即用户可以点击按钮添加销售属性）↓ -->
                <!-- <el-button type="primary" @click="handlerForUserClickTheAddSaleAttributeButton" :disabled="aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute?false:true" icon="Plus" size="default" style="margin-left: 10px;">添加销售属性</el-button> -->
                <el-button type="primary" @click="handlerForUserClickTheAddSaleAttributeButton" icon="Plus"
                    size="default" style="margin-left: 10px;">添加销售属性</el-button>
            </el-form-item>
            <el-form-item>
                <!-- 使用表格来展示“销售属性”及属性值↓ -->
                <el-table border style="margin: 10px 0px;" :data="anArrayBeUsedToTheStoreSalesAttributeOfASpu">
                    <el-table-column label="序号" align="center" type="index" width="80px"></el-table-column>
                    <el-table-column label="销售属性名称" align="center" width="120px" prop="saleAttrName"></el-table-column>
                    <el-table-column label="属性值" align="center">
                        <!-- 注：在此处，“row”就是“当前SPU已有的销售属性对象”↓ -->
                        <template #default="{ row, $index }">
                            <!-- <el-tag style="margin: 0px 5px;" v-for="(item,index) in row.saleAttrValueList" :key="item.id" closable @close="handlerForDeleteTag(item, index, row.saleAttrValueList.length)"> -->
                            <el-tag style="margin: 0px 5px;" v-for="(item, index) in row.saleAttrValueList"
                                :key="item.id" closable @close="row.saleAttrValueList.splice($index, 1)">
                                {{ item.saleAttrValueName }}
                            </el-tag>
                            <el-input v-if="row.flag == true"
                                @blur="handlerForChangeTheElInputComponentToPreviewMode(row)"
                                v-model="row.saleAttrValue" placeholder="请您输入属性值" size="small" width="120px"></el-input>
                            <el-button v-else type="primary" size="small" icon="Plus"
                                @click="handlerForChangeTheElInputComponentToEditMode(row)"></el-button>
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" align="center" width="120px">
                        <template #default="{ row, $index }">
                            <el-button type="danger" size="small" icon="Delete"
                                @click="anArrayBeUsedToTheStoreSalesAttributeOfASpu.splice(row, $index, 1)"></el-button>
                        </template>
                    </el-table-column>
                </el-table>
            </el-form-item>
            <el-form-item>
                <div class="saveAndCancelButtonIAtTheBottomOfTheForm">
                    <!-- 注：由于在模板中访问用“ref”定义的变量时，编译器会把该变量自动解包，以直接访问该变量引用的“原始数据”（即其“value”属性的值），因此在下面的这一行代码中，开发者访问“anObjectBeUsedToStoreTheSpuThatHaveBeenHad.spuSaleAttrList”时，不需要（也不能）在“anObjectBeUsedToStoreTheSpuThatHaveBeenHad”的后面加上“.value”，否则控制台中会报错↓ -->
                    <!-- <el-button type="primary" size="default" :disabled="anObjectBeUsedToStoreTheSpuThatHaveBeenHad.spuSaleAttrList.length>0?false:true" @click="handlerForUserClickTheSaveButton">保存</el-button> -->
                    <el-button type="primary" size="default"
                        :disabled="anArrayBeUsedToTheStoreSalesAttributeOfASpu.length > 0 ? false : true"
                        @click="handlerForUserClickTheSaveButton">保存</el-button>
                    <!-- 注：由于属性接口现在有故障（不返回数据），所以不为保存按钮添加禁用效果↓ -->
                    <!-- <el-button type="primary" size="default" @click="handlerForUserClickTheSaveButton">保存</el-button> -->
                    <el-button type="default" size="default" @click="handlerForUserClickTheCancelButton">取消</el-button>
                </div>
            </el-form-item>
        </el-form>
    </div>
</template>

<script lang="ts" setup name="spuForm">
import {
    requestAllOfTheTrademarkInfomation,
    requestTheImageListOfAProductThatBelongsToASpecificCategory3AndIsOnSaleNow,
    requestTheSalesAttributeOfASpu,
    requestAllOfSaleAttributesInThisProject,
    requestAddANewSpuOrUpdateTheInformationOfAnExistingSpu,
} from "@/api/product/spu"
import type {
    typeOfObjectThatRepresentsAnSpu,
    typeOfResponseDataOfTheApiThatGetsImagesOfAnSpu,
    typeOfResponseDataOfTheApiThatGetsSaleAttributesOfAnSpu,
    typeOfResponseDataOfTheApiThatGetAllOfSaleAttributesInThisProject,
    typeOfObjectThatStoresInformationOfATrademark,
    typeOfObjectThatRepresentsAnSaleAttribute,
    typeOfObjectThatRepresentsAnAttribute,
    typeOfObjectThatStoresInformationAboutTheImageOfAnSpu,
    typeOfObjectThatRepresentsAnSaleAttributeValue,
} from "@/api/product/spu/type"
import { ElMessage } from "element-plus"
// 此处定义了一个名为“changeScene”的事件，以便在这个组件（子组件）中触发该事件↓
let emit = defineEmits(['changeScene'])
import { ref, computed } from 'vue'
let anArrayBeUsedToStoreAllOfTheTrademarkInfomation = ref<typeOfObjectThatStoresInformationOfATrademark[]>([]) // 定义一个数组，它被用来存储全部品牌的数据
// 定义一个数组，它被用来存储某个SPU下面的全部在售商品的图片列表↓
let imageList = ref<typeOfObjectThatStoresInformationAboutTheImageOfAnSpu[]>([])
let anArrayBeUsedToTheStoreSalesAttributeOfASpu = ref<typeOfObjectThatRepresentsAnSaleAttribute[]>([]) // 定义一个数组，它被用来存储某个SPU的销售属性
let anArrayBeUsedToStoreAllOfSaleAttributesInThisProject = ref<typeOfObjectThatRepresentsAnAttribute>([]) // 定义一个数组，它被用来存储项目中的全部销售属性
let anObjectBeUsedToStoreTheSpuThatHaveBeenHad = ref<typeOfObjectThatRepresentsAnSpu>({
    // 定义一个对象，它被用来存储SPU数据
    // id: 0, // 某个SPU的id（因为新增SPU时ID由后台服务器自动生成，所以在此处不需要存储ID，因此注释这一行代码）
    spuName: "", // 某个SPU的名称
    description: "", // 某个SPU的描述信息
    category3Id: "", // 某个SPU所在的三级分类的id
    tmId: "", // 品牌id
    spuSaleAttrList: [], // 某个SPU的销售属性的集合（即销售属性的所在数组）
    spuImageList: [], // 某个SPU的图片的集合（即图片所在的数组）（它被用于在这个SPU的照片墙上显示图片）
    createTime: "",
    updateTime: "",
    spuPosterList: []
})
let isThedialogForPriviewPictureVisible = ref<boolean>(false) // 定义一个布尔值，它被用来控制“图片预览对话框”的显示与隐藏
let UrlForPreviewImageInThedialog = ref<string>('') // 定义一个字符串，它被用来存储“图片预览对话框”中显示的图片的URL
let aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute = ref<string>('') // 定义一个字符串，它被用来收集未被选择的销售属性的ID和名称

/**
 * 函数“handlerForUserClickTheCancelButton”被用于“处理用户点击取消按钮时发生的事件”
 */
function handlerForUserClickTheCancelButton() {
    // 使用自定义事件“changeScene”来通知父组件切换场景，以显示包含表格的“div”元素，用这个表格来展示“已有SPU的数据”↓
    // emit('changeScene', 'aDivElementIncludeTable')
    emit('changeScene', {flag:'aDivElementIncludeTable',params:'updateSpu'})
}
/**
 * @description 函数“initDataOfTheSpuThatBeAdded”是被用于“初始化新增SPU数据”的函数
 * @param anSpu 被用于接收父组件传递过来的已有SPU数据
 */
async function initDataOfTheSpuThatBeAdded(Category3Id: number | string) {
    // 在用户每次点击“添加SPU”按钮时，先清空上次操作后，在界面上残留的数据↓
    Object.assign(anObjectBeUsedToStoreTheSpuThatHaveBeenHad, {
        spuName: "",
        description: "",
        category3Id: "",
        tmId: "",
        spuSaleAttrList: [],
        spuImageList: [],
        createTime: "",
        updateTime: "",
        spuPosterList: []
    })
    imageList.value = [] // 清空图片列表
    anArrayBeUsedToTheStoreSalesAttributeOfASpu.value = [] // 清空销售属性列表
    aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute.value = '' // 清空未被选择的销售属性的ID和名称
    anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value.category3Id = Category3Id // 接收父组件传递过来的三级分类的ID
    console.log('初始化新增SPU数据的函数被调用了')
    let result: typeOfResponseDataOfTheApiThatGetsImagesOfAnSpu = await requestAllOfTheTrademarkInfomation() // 请求获取所有品牌的信息
    let anotherResult: typeOfResponseDataOfTheApiThatGetAllOfSaleAttributesInThisProject = await requestAllOfSaleAttributesInThisProject() // 请求获取项目中的全部销售属性
    // 存储数据↓
    anArrayBeUsedToStoreAllOfTheTrademarkInfomation.value = result.data
    anArrayBeUsedToStoreAllOfSaleAttributesInThisProject.value = anotherResult.data

}
/**
 * 初始化已有SPU数据的函数
 * @param anSpu 它是一个对象，它代表了已有的SPU数据
 */
async function initDataOfTheSpuThatHaveBeenHad(anSpu: typeOfObjectThatRepresentsAnSpu) {
    anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value = anSpu // 接收父组件传递过来的已有SPU数据
    console.log('初始化已有SPU数据的函数被调用了')
    console.log(anSpu) // 打印出传入的数据（控制台中显示：“Proxy(Object) {id: 205, createTime: '2024-12-07 09:01:42', updateTime: '2024-12-07 09:01:42', spuName: '你好呀', description: '·12', …}”）
    // 获取全部品牌的数据↓
    let result: typeOfResponseDataOfTheApiThatGetsImagesOfAnSpu = await requestAllOfTheTrademarkInfomation() // 请求获取所有品牌的信息
    console.log(result) // 打印出请求到的数据（控制台中显示：“{code: 200, message: '成功', data: Array(1859), ok: true}”）
    let anotherResult = await requestTheImageListOfAProductThatBelongsToASpecificCategory3AndIsOnSaleNow(anSpu.id as number) // 请求获取属于某一个三级分类的SPU下面的全部在售商品的图片列表（此处把参数的类型断言为number）
    console.log(anotherResult)
    let theThirdResult: typeOfResponseDataOfTheApiThatGetsSaleAttributesOfAnSpu = await requestTheSalesAttributeOfASpu(anSpu.id as number) // 请求获取某个SPU的销售属性
    console.log(theThirdResult)
    let thefourthResult: typeOfResponseDataOfTheApiThatGetAllOfSaleAttributesInThisProject = await requestAllOfSaleAttributesInThisProject() // 请求获取项目中的全部销售属性
    console.log(thefourthResult)
    anArrayBeUsedToStoreAllOfTheTrademarkInfomation.value = result.data // 将请求到的数据赋值给“anArrayBeUsedToStoreAllOfTheTrademarkInfomation”变量（此处使用了“value”属性来访问响应式引用中的值）
    console.log(anArrayBeUsedToStoreAllOfTheTrademarkInfomation)
    // imageList.value = anotherResult.data // 存储商品图片列表
    /* 注：数组的map方法‌是JavaScript中的一个内置方法，用于遍历数组并对每个元素执行一个回调函数，然后返回一个新数组，其中包含对原数组每个元素执行操作后的结果。‌map方法不会改变原始数组‌，而是生成一个新的数组。 */
    // 注：此处使用了数组提供的“map”方法来处理发送请求时获取到的数据（在此处，处理数据时的做法是“遍历获取到的图片数组，把每一个图片的名称和网址重新封装为一个对象，并把这些对象作为成员添加到一个新的数组，然后把这个新数组保存到变量‘imageList’中”）↓
    imageList.value = anotherResult.map((item: typeOfObjectThatStoresInformationAboutTheImageOfAnSpu) => { return { name: item.imgName, url: item.imgUrl } })
    anArrayBeUsedToTheStoreSalesAttributeOfASpu.value = theThirdResult.data // 存储销售属性
    anArrayBeUsedToStoreAllOfSaleAttributesInThisProject.value = thefourthResult.data // 存储项目中的全部销售属性
}
/**
 * 函数“handlerForPictureCardPreview”被用于处理图片卡片预览事件（这个事件在用户点击照片墙中的预览按钮时被触发）
 * @param uploadedFile 被上传的文件对象（此处使用了“any”类型，因为它代表了任意类型的值）
 */
function handlerForPictureCardPreview(uploadedFile: any) {
    console.log('图片卡片预览事件被触发了')
    console.log(uploadedFile) // 打印出被点击的图片卡片的信息（控制台中显示：“Proxy(Object) {name: '小米商标.jpg', percentage: 100, status: 'uploading', size: 52135, raw: File, …}”）
    UrlForPreviewImageInThedialog.value = uploadedFile.url // 将与被点击的图片卡片对应的图片的URL赋值给“UrlForPreviewImageInThedialog”变量（此处使用了“value”属性来访问响应式引用中的值）
    isThedialogForPriviewPictureVisible.value = true // 显示被用于“预览图片”的对话框
}
/**
 * 函数“handlerForRemoveFile”被用于处理移除文件事件（这个事件在用户点击照片墙中的删除按钮时被触发）
 */
function handlerForRemoveFile() {
    console.log('移除文件事件被触发了')
}
/**
 * “handlerForBeforeUpload”函数被用于处理在上传文件之前发生的事件（这个事件在用户点击照片墙中的添加按钮时被触发）
 * @param file 被上传的文件对象
 */
function handlerForBeforeUpload(uploadedFile: any) {
    console.log('处理在上传文件之前发生的事件的函数被调用了')
    console.log(uploadedFile) // {uid: 1741575089098, name: '小米商标.jpg', lastModified: 1740902608410, lastModifiedDate: Sun Mar 02 2025 16:03:28 GMT+0800 (中国标准时间), webkitRelativePath: '', …}uid: 1741575089098lastModified: 1740902608410lastModifiedDate: Sun Mar 02 2025 16:03:28 GMT+0800 (中国标准时间) {}name: "小米商标.jpg"size: 52135type: "image/jpeg"webkitRelativePath: ""[[Prototype]]: File
    // 注：此处约束了被上传的文件的类型和格式，只有符合格式的图片文件才会被上传↓
    if (uploadedFile.type == 'image/jpeg' || uploadedFile.type == 'image/png' || uploadedFile.type == 'image/gif') {
        // 注：此处用下面的这个条件判断语句限制了上传的图片的大小，只有小于3MB的图片才会被允许上传（size的计量单位是“字节（Byte）”）↓
        if (uploadedFile.size / 1024 / 1024 < 3) {
            return true
        } else {
            ElMessage({
                type: 'error',
                message: '图片大小不能超过3MB',
            })
            return false
        }
    } else {
        ElMessage({
            type: 'error',
            message: '上传的图片文件的格式必须是JPEG、PNG或GIF',
        })
        return false
    }
}
/**
 * 函数“handlerForUserClickTheAddSaleAttributeButton”被用于处理用户点击添加销售属性按钮时发生的事件
 */
function handlerForUserClickTheAddSaleAttributeButton() {
    // alert('添加销售属性按钮被点击了')
    console.log('添加销售属性按钮被点击了')
    // 以冒号作为分隔符，分割字符串“aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute”中的ID和名称（注：“split”方法将返回一个数组，这个数组以分割后的字符串片段作为成员）↓
    // let anArrayBeUsedToStoreIdAndNameOfUnSelectedSaleAttribute = aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute.value.split(":")
    // 注：此处使用了“数组的解构赋值”语法来提取数组成员（即同时提取字符串中的ID和名称）↓
    let [baseSaleAttrId, saleAttrName] = aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute.value.split(":")
    // console.log(anArrayBeUsedToStoreIdAndNameOfUnSelectedSaleAttribute)
    let aNewObjectThatRepresentsTheSaleAttributeThatUnSelectedByTheUser: typeOfObjectThatRepresentsAnSaleAttribute = { baseSaleAttrId, saleAttrName, saleAttrValueList: [] } // 创建一个新的对象，它代表未被用户选中的销售属性
    anArrayBeUsedToTheStoreSalesAttributeOfASpu.value.push(aNewObjectThatRepresentsTheSaleAttributeThatUnSelectedByTheUser) // 将新创建的代表未被选中的销售属性的对象添加到数组“anArrayBeUsedToTheStoreSalesAttributeOfASpu”中（此处使用了“value”属性来访问响应式引用中的值）
    aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute.value = '' // 清空字符串“aVariableUsedToCollectIdAndNameOfUnSelectedSaleAttribute”中的内容

}
/**
 * 函数“handlerForChangeTheElInputComponentToEditMode”被用于处理“将el-input组件切换到编辑模式”的事件（这个事件在用户点击表格中的“添加属性值”按钮（一个图标为“加号”的按钮）时被触发）
 */
function handlerForChangeTheElInputComponentToEditMode(row: typeOfObjectThatRepresentsAnSaleAttribute) {
    // alert('添加属性值按钮被点击了')
    row.flag = true // 将代表销售属性的对象的“flag”属性设置为true，以切换el-input组件到编辑模式
    row.saleAttrValue = '' // 在代表销售属性的对象上动态地添加一个名为的“saleAttrValue”属性，赋予其初始值为空字符串
}
/**
 * 函数“handlerForChangeTheElInputComponentToPreviewMode”被用于处理将el-input组件切换到预览模式的事件（这个事件在用户让“文本输入框”失去焦点时发生）
 */
function handlerForChangeTheElInputComponentToPreviewMode(row: typeOfObjectThatRepresentsAnSaleAttribute) {
    console.log('将el-input组件切换到预览模式的函数被调用了')
    console.log(row) // Proxy(Object) {baseSaleAttrId: '', saleAttrName: undefined, saleAttrValueList: Array(0), flag: true, saleAttrValue: ''}
    let { baseSaleAttrId, saleAttrValue } = row // 使用对象的解构赋值语法来提取代表销售属性的对象中的“baseSaleAttrId”和“saleAttrValue”属性
    let anObjectBeUsedToStoreANewSaleAttributeValue: typeOfObjectThatRepresentsAnSaleAttributeValue = { baseSaleAttrId, saleAttrValueName: (saleAttrValue as string) } // 创建一个新的对象，它被用于存储一个新的销售属性值（注：此处使用了“类型断言语法”来将“saleAttrValue”的类型断言为字符串类型）
    // 排除非法情况（注：此处使用了“类型断言语法”来把“saleAttrValue”断言为“字符串”类型。如果不这样做，那么类型检查和推断系统会报错说“saleAttrValue”的类型可能是“undefined”）↓
    // 非法情况1：属性值为空字符串↓
    if ((saleAttrValue as string).trim() == '') {
        // 如果属性值为空，则弹出错误提示信息，并直接退出函数执行↓
        ElMessage({
            type: 'error',
            message: '属性值不能为空'
        })
        return
    } else {
        let duplicateAttributeValueNames = row.saleAttrValueList.find((item: typeOfObjectThatRepresentsAnSaleAttributeValue) => {
            return item.saleAttrValueName == saleAttrValue
        })
        console.log(duplicateAttributeValueNames) // 打印出重名的属性值（控制台中显示：Proxy(Object) {baseSaleAttrId: '', saleAttrValueName: '123'}）
        // 如果存在重名的属性值，则弹出错误提示信息，并直接退出函数执行↓
        if (duplicateAttributeValueNames) {
            ElMessage({
                type: 'error',
                message: '属性值不能重复'
            })
            return
        } else {
            row.saleAttrValueList.push(anObjectBeUsedToStoreANewSaleAttributeValue) // 将创建的代表新销售属性值的对象添加到数组“saleAttrValueList”中
            row.flag = false // 将代表销售属性的对象的“flag”属性设置为false，以切换el-input组件到预览模式
        }
    }
}
/**
 * 函数“handlerForDeleteTag”被用于处理删除标签的事件（这个事件在用户点击销售属性值旁边的关闭图标时发生）
 * @param index 索引值
 * @param arrayLength 数组的长度
 */
/* function handlerForDeleteTag(item: typeOfObjectThatRepresentsAnSaleAttributeValue, index: number, arrayLength: number) {
    const row = findRowContainingItem(item);
    if (row) {
        row.saleAttrValueList.splice(index, 1); // 从数组“row.saleAttrValueList”中移除索引值为“index”的元素，从而实现删除标签的目的
    } else {
        console.error('没有找到与被删除的标签对应的销售属性值对象');
    }
} */
/**
 * 函数“findRowContainingItem”被用于查找包含指定销售属性值对象的行对象（即销售属性对象）。如果找到，则返回该行（返回这个销售属性对象）；否则，则返回undefined
 * @param item 被删除的标签对应的销售属性值对象
 */
/* function findRowContainingItem(item: typeOfObjectThatRepresentsAnSaleAttributeValue): typeOfObjectThatRepresentsAnSaleAttribute | undefined {
    // 遍历数组“anArrayBeUsedToTheStoreSalesAttributeOfASpu.value”中的每一个元素，找到包含指定销售属性值对象的行↓
    return anArrayBeUsedToTheStoreSalesAttributeOfASpu.value.find((row:typeOfObjectThatRepresentsAnSaleAttribute) => row.saleAttrValueList.includes(item));
} */
/**
 * 函数“handlerForUserClickTheSaveButton”被用于处理用户点击保存按钮时发生的事件
 */
async function handlerForUserClickTheSaveButton() {
    console.log('保存按钮被点击了')
    // 在这个函数中需要做的事情：
    // 1.整理数据，使之符合后端要求的格式；
    anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value.spuImageList = imageList.value.map((item: typeOfObjectThatStoresInformationAboutTheImageOfAnSpu) => {
        return {
            imageName: item.name,
            // 如果是“更新SPU”，后端返回了图片的URL（注：返回数据中的“data”属性的值就是“URL”），那么就使用这个URL；否则（即“添加SPU”），就用图片对象中的URL↓
            imageUrl: (item.response && item.response.data) || item.url
        }
    })
    anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value.spuSaleAttrList = anArrayBeUsedToTheStoreSalesAttributeOfASpu.value // 整理销售属性数据
    console.log(anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value) // Proxy(Object) {id: 355, createTime: '2025-02-27 09:06:03', updateTime: '2025-02-27 09:06:03', spuName: 'Mars', description: 'Kyle', …}
    // 2.发送请求来添加或更新SPU信息；
    let result = await requestAddANewSpuOrUpdateTheInformationOfAnExistingSpu(anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value)
    console.log(result) // {code: 201, message: '失败', data: null, ok: false}（由于目前的接口有故障，所以控制台输出这个内容）
    // 3.在“请求成功”和“请求失败”时都弹出提示信息
    if (result.code == 200) {
        ElMessage({
            type: 'success',
            message: anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value.id ? '更新SPU成功' : '添加SPU成功',
        })
        // 通知父组件切换场景，显示表格↓
        // emit('changeScene', 'aDivElementIncludeTable')
        emit('changeScene', {flag:'aDivElementIncludeTable',params:anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value.id?'updateSpu':'addSpu'})
    } else {
        ElMessage({
            type: 'error',
            message: anObjectBeUsedToStoreTheSpuThatHaveBeenHad.value.id ? '更新SPU失败' : '添加SPU失败',
        })
        emit('changeScene', 'aDivElementIncludeTable')
    }
}
// 计算属性“saleAttributesThatUnSelectedByTheUser”被用于计算未被用户选中的销售属性的集合↓
let saleAttributesThatUnSelectedByTheUser = computed(() => {
    // 项目中全部的销售属性共有三个：颜色、版本、尺码。当前已有的销售属性是：颜色、版本
    /* 注：此处调用了数组提供的“every”方法来检测数组中的所有元素是否都满足指定的条件。以下内容是文心快码对此处的详细解释：
    在JavaScript中，数组的every方法是一个非常实用的工具，用于检测数组中的所有元素是否都满足指定的条件。以下是对every方法的详细解释：
    1. 基本功能:every方法用于测试数组的所有元素是否都通过了被提供的函数测试。它返回一个布尔值：如果数组的每个元素都执行了提供的函数，并且该函数对每个元素都返回true，则every方法返回true；否则，它返回false。
    2. 语法及其参数：“array.every(callback(currentValue, index, array), thisArg)”
    a.callback：为数组中每个元素执行的函数，接受三个参数：currentValue（当前元素的值），index（当前元素的索引），array（调用every方法的数组）。
    b.thisArg（可选）：执行callback时使用的this值。
    3. 简单示例：
    // const array = [1, 2, 3, 4, 5];
    // 检查数组中是否所有元素都大于0
    // const allPositive = array.every(element => element > 0);
    // console.log(allPositive); // 输出: true
    // 检查数组中是否所有元素都大于2
    // const allGreaterThanTwo = array.every(element => element > 2);
    // console.log(allGreaterThanTwo); // 输出: false
    4. 根据回调函数的结果决定整个数组是否满足条件：every方法会遍历数组的每一项，并对每一项执行提供的回调函数。如果回调函数对数组中的任何一项返回false，every方法会立即返回false，并且不会继续测试数组中的剩余元素。如果遍历完数组后，每一项都返回true，则every方法返回true。
    5. 与some、filter等其他数组方法的不同之处：‌some方法‌：与every方法相反，some方法测试数组中是否至少有一个元素通过了被提供的函数测试。只要有一个元素通过测试，some方法就返回true。
    // const array = [1, 2, 3, 4, 5];
    // const hasEven = array.some(element => element % 2 === 0);
    // console.log(hasEven); // 输出: true
    // filter方法‌：filter方法创建一个新数组，其包含通过所提供函数实现的测试的所有元素。它不会返回布尔值，而是返回一个新数组。
    // const array = [1, 2, 3, 4, 5];
    // const evenNumbers = array.filter(element => element % 2 === 0);
    // console.log(evenNumbers); // 输出: [2, 4]
    // 综上所述，every方法是JavaScript中用于数组元素条件检查的一个非常有用的工具，它根据回调函数的结果决定整个数组是否满足特定条件。↓ */
    let anArrayBeUsedToStoreAllOfUnselectedSaleAttributes = anArrayBeUsedToStoreAllOfSaleAttributesInThisProject.value.filter((item: typeOfObjectThatRepresentsAnSaleAttribute) => {
        return anArrayBeUsedToStoreAllOfSaleAttributesInThisProject.value.every((item1: typeOfObjectThatRepresentsAnSaleAttribute) => {
            return item.name != item1.saleAttrName
        })
    })
    return anArrayBeUsedToStoreAllOfUnselectedSaleAttributes
})
// 注：由于子组件保护了被书写在使用了“setup语法糖”的“script”标签的标签体中的变量和函数，因此需要通过“defineExpose”来对外暴露这些变量和函数，供父组件使用↓
defineExpose({ initDataOfTheSpuThatHaveBeenHad, initDataOfTheSpuThatBeAdded })
</script>

<style scoped>
/* 让保存和取消按钮所在的div元素在表单底部水平方向和垂直方向上居中对齐的样式设置↓ */
.saveAndCancelButtonIAtTheBottomOfTheForm {
    width: 100%;
    /* 容器宽度占满父元素 */
    height: 100%;
    /* 如果需要按钮垂直居中，可以设置容器的高度 */
    display: flex;
    justify-content: center;
    /* 水平居中 */
    align-items: center;
    /* 垂直居中 */
}
</style>